/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Server.domain;

import Server.domain.ai.AIType;
import Server.domain.items.Item;
import Server.persistentie.ItemFactory;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 *
 * @author Ripper
 */
public class GameLevel 
{   
    private GameSession session;
    
    private List<Mob> monsters;
    private List<Player> players;
    private List<Plain> plains;
    private List<Projectile> projectiles;
    private List<DecorativeElement> decorativeElements;
    
    private Player currentAttacker;
    
    private ItemFactory lootBag;
    
    public GameLevel(GameSession gs)
    {
        session = gs;
        monsters = new ArrayList<Mob>();
        players = new ArrayList<Player>();
        plains = new ArrayList<Plain>();
        projectiles = new ArrayList<Projectile>();
        decorativeElements = new ArrayList<DecorativeElement>();
        lootBag = new ItemFactory();
        
    }
    public Player getCurrentAttacker()
    {
        return currentAttacker;
    }
    public GameLevel(GameSession gs, List<Mob> mobs, List<Player> plrs, List<DecorativeElement> eles,
            List<Plain> plaines)
    {
        session = gs;
        setMonsters(mobs);
        setPlayers(plrs);
        decorativeElements = eles;
        plains = plaines;
        projectiles = new ArrayList<Projectile>();
        lootBag = new ItemFactory();
    }
    public void prepareSpawnArea()
    {
        //TODO
        
        //temp
        Color[] colors = {new Color(255,0,0),
                          new Color(0,255,0),
                          new Color(0,0,255),
                          new Color(255,0,255)};
        Mob m = new Mob(this, "Crazy Robot", 1, 2, colors, 2, 1000, 1000, 0.2, 10, 10, 10, 10, 0, 2, 0, 0, 
                AIType.INACTIVE_AI, 20, 10000, 1.0, 2);
        m.setX(300);
        m.setY(300);
        monsters.add(m);
        
        Mob m2 = new Mob(this, "Crazy Robot", 2, 2, colors, 2, 1000, 1000, .01, 100, 10, 10, 10, 0, 2, 0, 0, 
                AIType.INACTIVE_AI, 20, 10000, 1.0, 2);
        m2.setX(425);
        m2.setY(300);
        monsters.add(m2);
        
        Color[] colorez = {new Color(255,0,0), new Color(0,255,0), new Color(137,65,56), new Color(0,0,255)};
        Mob m4 = new Mob(this, "critter", 4, 99, colorez, 2, 1000, 50, 0, 2, 10, 0, 0, 0, 2, 0, 0, 
                AIType.STUPID_CHASE_AI, 12, 50, 0.5, 1);
        m4.setX(500);
        m4.setY(500);
        monsters.add(m4);
        m4 = new Mob(this, "critter", 5, 99, colorez, 2, 1000, 50, 0, 2, 10, 0, 0, 0, 2, 0, 0, 
                AIType.STUPID_CHASE_AI, 12, 50, 0.5, 1);
        m4.setX(550);
        m4.setY(500);
        monsters.add(m4);
        m4 = new Mob(this, "critter", 6, 99, colorez, 2, 1000, 50, 0, 2, 10, 0, 0, 0, 2, 0, 0, 
                AIType.STUPID_CHASE_AI, 12, 50, 0.5, 1);
        m4.setX(600);
        m4.setY(500);
        monsters.add(m4);
        
        Mob m3 = new Mob(this, "Crazy... tentaclething?", 3, 4, colors, 2, 1000, 100000, 26, 1, 1, 1, 1, 0, 2, 0, 0, 
                AIType.INACTIVE_AI, 25, 10000, 1.0, 5);
        m3.setX(367);
        m3.setY(425);
        monsters.add(m3);
        
        for(int a = 0; a < 3; a++)
        {
            Color[] rockCols = new Color[4];
            for(int b = 0; b < 4; b++)
            {
                rockCols[b] = new Color(200,200,200);
            }
            
            DecorativeElement rock = new DecorativeElement(a * 250 + 200, 500, 25, a+1, 1000, rockCols);
            decorativeElements.add(rock);
            
            Color[] bushCols = new Color[4];
            for(int b = 0; b < 4; b++)
            {
                bushCols[b] = new Color(150,255,150);
            }
            
            DecorativeElement bush = new DecorativeElement(a * 200 + 150, 60, 25, a+3+1, 1001, bushCols);
            decorativeElements.add(bush);
        }
        
        
        int plainXgridsize = 8;
        int plainYgridsize = 6;
        Plain p = new Plain(plainXgridsize,plainYgridsize,0,0);
        for(int a = 0; a < plainXgridsize; a++)
        {
            for(int b = 0; b < plainYgridsize; b++)
            {
                Tile t = new Tile(10000,true);
                p.setTileAt(a, b, t);
            }
        }
        addPlain(p);
        
    }
    public String getNewConnectionInformation()
    {
        String initialData = "";
        
        for(Mob m: monsters)
        {
            initialData += "m_add:"+m.getNecessaryInformation()+";";
        }
        for(Player p: players)
        {
            initialData += "p_add:"+p.getNecessaryInformation()+";";
        }
        for(DecorativeElement d: decorativeElements)
        {
            initialData += "de_add:"+d.getNecessaryInformation()+";";
        }
        for(Plain p: plains)
        {
            initialData += "pln_add:"+p.getNecessaryInformation()+";";
        }
        for(Projectile f: projectiles)
        {
            initialData += "prj_add:"+f.getNecessaryInformation()+";";
        }
        
        return initialData;
    }
    public String getGlobalLocationData()
    {
        String data = "globallocations:";
        
        for(Player p: players)
        {
            data += p.getLocationData() + "-";
        }
        for(Mob m: monsters)
        {
            data += m.getLocationData() + "-";
        }
        for(Projectile f: projectiles)
        {
            data += f.getLocationData() + "-prj";
        }
        
        data = data.substring(0, data.length() - 1);
        
        return data;
    }
    
    public boolean canMoveTo(double newX, double newY, Entity source)
    {
        for(Mob m: monsters)
        {
            if(source != m && wouldEntitiesCollide(m,source,newX,newY))
            {
                return false;
            }
        }
        for(Player p: players)
        {
            if(source != p && wouldEntitiesCollide(p,source,newX,newY))
            {
                return false;
            }
        }
        for(DecorativeElement de: decorativeElements)
        {
            if(wouldEntitiesCollide(de, source, newX, newY))
            {
                return false;
            }
        }
        
        //TODO
        
        return true;
    }
    
    public boolean wouldEntitiesCollide(WorldOccupant bystander, WorldOccupant jaywalker, double newX, double newY)
    {
        if(bystander.getHitboxradius() == 0 || jaywalker.getHitboxradius() ==0)
        {
            return false;
        }
        
        //double distanceToNew = Math.sqrt(Math.pow(bystander.getX() - newX,2) + Math.pow(bystander.getY() - newY,2));
        double distanceToNew = MathHelper.getDistanceBetween(bystander, newX, newY);
        
        if(distanceToNew < (bystander.getHitboxradius() + jaywalker.getHitboxradius()))
        {
            //if entities are already colliding, they shouldn't be blocked by each other when trying to un-collide from each other
            //double distanceToOld = Math.sqrt(Math.pow(bystander.getX() - jaywalker.getX(),2) + Math.pow(bystander.getY() - jaywalker.getY(),2));
            double distanceToOld = MathHelper.getDistanceBetween(bystander, jaywalker);
            if(distanceToNew > distanceToOld)
            {
                return false;
            }
            
            return true;
        }
        return false;
    }
    
    public void update()
    {
        for(Mob m: monsters)
        {
            m.update();
        }
        for(Player p: players)
        {
            p.update();
        }
        for(Projectile p: projectiles)
        {
            p.update();
        }
        
        /*if(players.size() > 0)
        {
            Player p = players.get(0);
            System.out.println("player "+p.getPlayerName()+": X="+p.getX()+", Y="+p.getY());
        }*/
        
        ListIterator<Mob> i = monsters.listIterator();
        while(i.hasNext())
        {
            Mob m = i.next();
            
            if(!m.isAlive())
            {
                int xp = m.getXp();
                int playersPlaying = players.size();
                
                if(playersPlaying > 0)
                {
                    int xpPerPlayer = xp / playersPlaying;
                    
                    for(Player p: players)
                    {
                        p.addExperience(xpPerPlayer);
                        //TODO: add a little "+x XP!" text
                    }
                    
                    boolean dropLoot = TheRandominator.getRandom().nextInt(100) 
                            < m.getChanceToDropLoot() * 100;
                    
                    if(dropLoot)
                    {
                        for(int c = 0; c < m.getLootDropAmount(); c++)
                        {
                            Player luckyperson = getPlayers().get(TheRandominator.getRandom().nextInt(playersPlaying));
                            Item itan = lootBag.getRandomLootItemForLevel(luckyperson.getLevel());
                            luckyperson.addItem(itan);
                        }
                    }
                }
                
                session.tellGameSession("m_rm:"+m.getMonsterID());
                i.remove();
            }
        }
        ListIterator<Projectile> ii = projectiles.listIterator();
        while(ii.hasNext())
        {
            Projectile p = ii.next();
            
            if(!p.isActive())
            {
                session.tellGameSession("prj_rm:"+p.getId());
                ii.remove();
            }
        }
        //TODO
    }

    public List<Mob> getMonsters() { return monsters; }
    public final void setMonsters(List<Mob> monsters) { this.monsters = monsters; }
    public List<Player> getPlayers() { return players; }
    public final void setPlayers(List<Player> players) { this.players = players; }
    public void removePlayer(Player selectedPlayer) 
    {
        if(players.contains(selectedPlayer))
        {
            players.remove(selectedPlayer);
            session.tellGameSession("p_rm:"+selectedPlayer.getPlayerName());
        }
    }
    public void addPlayer(Player selectedPlayer)
    {
        players.add(selectedPlayer);
        
        session.tellGameSession("p_add:"+selectedPlayer.getNecessaryInformation());
    }
    public void addProjectile(Projectile p)
    {
        if(p != null)
        {
            projectiles.add(p);

            session.tellGameSession("prj_add:"+p.getNecessaryInformation());
        }
    }
    public void addMonster(Mob m)
    {
        monsters.add(m);
        
        session.tellGameSession("m_add:"+m.getNecessaryInformation());
    }
    public void addPlain(Plain p)
    {
        plains.add(p);
        
        session.tellGameSession("pln_add:"+p.getNecessaryInformation());
    }
    public void addDecorativeElement(DecorativeElement de)
    {
        decorativeElements.add(de);
        
        session.tellGameSession("de_add:"+de.getNecessaryInformation());
    }
    public GameSession getSession()
    {
        return session;
    }
    
    public void playerAttacks(Player p)
    {
        currentAttacker = p;
    }
    public void playerDoneAttacking()
    {
        currentAttacker = null;
    }

    public List<DecorativeElement> getDecorativeElements() {
        return decorativeElements;
    }

    public void setDecorativeElements(List<DecorativeElement> decorativeElements) {
        this.decorativeElements = decorativeElements;
    }
    
    
}
